/* ---------------------------------------------------------------------------- */
/*                  Atmel Microcontroller Software Support                      */
/*                       SAM Software Package License                           */
/* ---------------------------------------------------------------------------- */
/* Copyright (c) 2015, Atmel Corporation                                        */
/*                                                                              */
/* All rights reserved.                                                         */
/*                                                                              */
/* Redistribution and use in source and binary forms, with or without           */
/* modification, are permitted provided that the following condition is met:    */
/*                                                                              */
/* - Redistributions of source code must retain the above copyright notice,     */
/* this list of conditions and the disclaimer below.                            */
/*                                                                              */
/* Atmel's name may not be used to endorse or promote products derived from     */
/* this software without specific prior written permission.                     */
/*                                                                              */
/* DISCLAIMER:  THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR   */
/* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE   */
/* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,      */
/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,  */
/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    */
/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING         */
/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
/* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                           */
/* ---------------------------------------------------------------------------- */

/** \file
 *  Implements functions for Controller Area Network (CAN)
 *  peripheral operations.
 */
/** \addtogroup can_module
 *@{*/


/*----------------------------------------------------------------------------
 *        Headers
 *----------------------------------------------------------------------------*/
#ifndef __rtems__
#include "board.h"
#endif /* __rtems__ */
#include "chip.h"
#include "mcan_config.h"
#include <assert.h>
/*---------------------------------------------------------------------------
 *      Definitions
 *---------------------------------------------------------------------------*/
#define MAILBOX_ADDRESS(address) (0xFFFC & (address))

#define CAN_CLK_FREQ_HZ               MCAN_PROG_CLK_FREQ_HZ

#define MCAN0_TSEG1                   (MCAN0_PROP_SEG + MCAN0_PHASE_SEG1)
#define MCAN0_TSEG2                   (MCAN0_PHASE_SEG2)
#define MCAN0_BRP                     ((uint32_t) (((float) CAN_CLK_FREQ_HZ / \
									   ((float)(MCAN0_TSEG1 + MCAN0_TSEG2 + 3) *\
										(float) MCAN0_BIT_RATE_BPS)) - 1))
#define MCAN0_SJW                     (MCAN0_SYNC_JUMP - 1)
#define MCAN0_FTSEG1                  (MCAN0_FAST_PROP_SEG + MCAN0_FAST_PHASE_SEG1)
#define MCAN0_FTSEG2                  (MCAN0_FAST_PHASE_SEG2)
#define MCAN0_FBRP                    ((uint32_t) (((float) CAN_CLK_FREQ_HZ / \
									   ((float)(MCAN0_FTSEG1 + MCAN0_FTSEG2 + 3) * \
										(float) MCAN0_FAST_BIT_RATE_BPS)) - 1))
#define MCAN0_FSJW                    (MCAN0_FAST_SYNC_JUMP - 1)

#define MCAN0_STD_FLTS_WRDS           (MCAN0_NMBR_STD_FLTS)
/* 128 max filters */
#define MCAN0_EXT_FLTS_WRDS           (MCAN0_NMBR_EXT_FLTS * 2)
/* 64 max filters */
#define MCAN0_RX_FIFO0_WRDS           (MCAN0_NMBR_RX_FIFO0_ELMTS * \
									   ((MCAN0_RX_FIFO0_ELMT_SZ/4) + 2))
/* 64 elements max */
#define MCAN0_RX_FIFO1_WRDS           (MCAN0_NMBR_RX_FIFO1_ELMTS *\
									   ((MCAN0_RX_FIFO1_ELMT_SZ/4) + 2))
/* 64 elements max */
#define MCAN0_RX_DED_BUFS_WRDS            (MCAN0_NMBR_RX_DED_BUF_ELMTS * \
		((MCAN0_RX_BUF_ELMT_SZ/4) + 2))
/* 64 elements max */
#define MCAN0_TX_EVT_FIFO_WRDS        (MCAN0_NMBR_TX_EVT_FIFO_ELMTS * 2)
/* 32 elements max */
#define MCAN0_TX_DED_BUF_WRDS         (MCAN0_NMBR_TX_DED_BUF_ELMTS * \
									   ((MCAN0_TX_BUF_ELMT_SZ/4) + 2))
/* 32 elements max */
#define MCAN0_TX_FIFO_Q_WRDS          (MCAN0_NMBR_TX_FIFO_Q_ELMTS *\
									   ((MCAN0_TX_BUF_ELMT_SZ/4) + 2))
/* 32 elements max */

#define MCAN1_TSEG1                   (MCAN1_PROP_SEG + MCAN1_PHASE_SEG1)
#define MCAN1_TSEG2                   (MCAN1_PHASE_SEG2)
#define MCAN1_BRP                     ((uint32_t) (((float) CAN_CLK_FREQ_HZ / \
									   ((float)(MCAN1_TSEG1 + MCAN1_TSEG2 + 3) *\
										(float) MCAN1_BIT_RATE_BPS)) - 1))
#define MCAN1_SJW                     (MCAN1_SYNC_JUMP - 1)
#define MCAN1_FTSEG1                  (MCAN1_FAST_PROP_SEG + MCAN1_FAST_PHASE_SEG1)
#define MCAN1_FTSEG2                  (MCAN1_FAST_PHASE_SEG2)
#define MCAN1_FBRP                    ((uint32_t) (((float) CAN_CLK_FREQ_HZ /\
									   ((float)(MCAN1_FTSEG1 + MCAN1_FTSEG2 + 3) *\
										(float) MCAN1_FAST_BIT_RATE_BPS)) - 1))
#define MCAN1_FSJW                    (MCAN1_FAST_SYNC_JUMP - 1)

#define MCAN1_STD_FLTS_WRDS           (MCAN1_NMBR_STD_FLTS)
/* 128 max filters */
#define MCAN1_EXT_FLTS_WRDS           (MCAN1_NMBR_EXT_FLTS * 2)
/* 64 max filters */
#define MCAN1_RX_FIFO0_WRDS           (MCAN1_NMBR_RX_FIFO0_ELMTS * \
									   ((MCAN1_RX_FIFO0_ELMT_SZ/4) + 2))
/* 64 elements max */
#define MCAN1_RX_FIFO1_WRDS           (MCAN1_NMBR_RX_FIFO1_ELMTS *\
									   ((MCAN1_RX_FIFO1_ELMT_SZ/4) + 2))
/* 64 elements max */
#define MCAN1_RX_DED_BUFS_WRDS            (MCAN1_NMBR_RX_DED_BUF_ELMTS * \
		((MCAN1_RX_BUF_ELMT_SZ/4) + 2))
/* 64 elements max */
#define MCAN1_TX_EVT_FIFO_WRDS        (MCAN1_NMBR_TX_EVT_FIFO_ELMTS * 2)
/* 32 elements max */
#define MCAN1_TX_DED_BUF_WRDS         (MCAN1_NMBR_TX_DED_BUF_ELMTS * \
									   ((MCAN1_TX_BUF_ELMT_SZ/4) + 2))
/* 32 elements max */
#define MCAN1_TX_FIFO_Q_WRDS          (MCAN1_NMBR_TX_FIFO_Q_ELMTS * \
									   ((MCAN1_TX_BUF_ELMT_SZ/4) + 2))
/* 32 elements max */

/* validate CAN0 entries */
#if (MCAN0_TSEG1 > 63)
	#error "Invalid CAN0 TSEG1"
#endif
#if (MCAN0_TSEG2 > 15)
	#error "Invalid CAN0 TSEG2"
#endif
#if (MCAN0_SJW > 15)
	#error "Invalid CAN0 SJW"
#endif
#if (MCAN0_FTSEG1 > 15)
	#error "Invalid CAN0 FTSEG1"
#endif
#if (MCAN0_FTSEG2 > 7)
	#error "Invalid CAN0 FTSEG2"
#endif
#if (MCAN0_FSJW > 3)
	#error "Invalid CAN0 FSJW"
#endif

#if (MCAN0_NMBR_STD_FLTS > 128)
	#error "Invalid CAN0 # of Standard Filters"
#endif
#if (MCAN0_NMBR_EXT_FLTS > 64)
	#error "Invalid CAN0 # of Extended Filters"
#endif
#if (MCAN0_NMBR_RX_FIFO0_ELMTS > 64)
	#error "Invalid CAN0 # RX FIFO 0 ELEMENTS"
#endif
#if (MCAN0_NMBR_RX_FIFO1_ELMTS > 64)
	#error "Invalid CAN0 # RX FIFO 0 ELEMENTS"
#endif
#if (MCAN0_NMBR_RX_DED_BUF_ELMTS > 64)
	#error "Invalid CAN0 # RX BUFFER ELEMENTS"
#endif
#if (MCAN0_NMBR_TX_EVT_FIFO_ELMTS > 32)
	#error "Invalid CAN0 # TX EVENT FIFO ELEMENTS"
#endif
#if ((MCAN0_NMBR_TX_DED_BUF_ELMTS + MCAN0_NMBR_TX_FIFO_Q_ELMTS)  > 32)
	#error "Invalid CAN0 # TX BUFFER ELEMENTS"
#endif

#if   (8 == MCAN0_RX_FIFO0_ELMT_SZ)
	#define MCAN0_RX_FIFO0_DATA_SIZE  (0u)
#elif (12 == MCAN0_RX_FIFO0_ELMT_SZ)
	#define MCAN0_RX_FIFO0_DATA_SIZE  (1u)
#elif (16 == MCAN0_RX_FIFO0_ELMT_SZ)
	#define MCAN0_RX_FIFO0_DATA_SIZE  (2u)
#elif (20 == MCAN0_RX_FIFO0_ELMT_SZ)
	#define MCAN0_RX_FIFO0_DATA_SIZE  (3u)
#elif (24 == MCAN0_RX_FIFO0_ELMT_SZ)
	#define MCAN0_RX_FIFO0_DATA_SIZE  (4u)
#elif (32 == MCAN0_RX_FIFO0_ELMT_SZ)
	#define MCAN0_RX_FIFO0_DATA_SIZE  (5u)
#elif (48 == MCAN0_RX_FIFO0_ELMT_SZ)
	#define MCAN0_RX_FIFO0_DATA_SIZE  (6u)
#elif (64 == MCAN0_RX_FIFO0_ELMT_SZ)
	#define MCAN0_RX_FIFO0_DATA_SIZE  (7u)
#else
	#error "Invalid CAN0 RX FIFO0 ELEMENT SIZE"
#endif

#if   (8 == MCAN0_RX_FIFO1_ELMT_SZ)
	#define MCAN0_RX_FIFO1_DATA_SIZE  (0u)
#elif (12 == MCAN0_RX_FIFO1_ELMT_SZ)
	#define MCAN0_RX_FIFO1_DATA_SIZE  (1u)
#elif (16 == MCAN0_RX_FIFO1_ELMT_SZ)
	#define MCAN0_RX_FIFO1_DATA_SIZE  (2u)
#elif (20 == MCAN0_RX_FIFO1_ELMT_SZ)
	#define MCAN0_RX_FIFO1_DATA_SIZE  (3u)
#elif (24 == MCAN0_RX_FIFO1_ELMT_SZ)
	#define MCAN0_RX_FIFO1_DATA_SIZE  (4u)
#elif (32 == MCAN0_RX_FIFO1_ELMT_SZ)
	#define MCAN0_RX_FIFO1_DATA_SIZE  (5u)
#elif (48 == MCAN0_RX_FIFO1_ELMT_SZ)
	#define MCAN0_RX_FIFO1_DATA_SIZE  (6u)
#elif (64 == MCAN0_RX_FIFO1_ELMT_SZ)
	#define MCAN0_RX_FIFO1_DATA_SIZE  (7u)
#else
	#error "Invalid CAN0 RX FIFO1 ELEMENT SIZE"
#endif

#if   (8 == MCAN0_RX_BUF_ELMT_SZ)
	#define MCAN0_RX_BUF_DATA_SIZE  (0u)
#elif (12 == MCAN0_RX_BUF_ELMT_SZ)
	#define MCAN0_RX_BUF_DATA_SIZE  (1u)
#elif (16 == MCAN0_RX_BUF_ELMT_SZ)
	#define MCAN0_RX_BUF_DATA_SIZE  (2u)
#elif (20 == MCAN0_RX_BUF_ELMT_SZ)
	#define MCAN0_RX_BUF_DATA_SIZE  (3u)
#elif (24 == MCAN0_RX_BUF_ELMT_SZ)
	#define MCAN0_RX_BUF_DATA_SIZE  (4u)
#elif (32 == MCAN0_RX_BUF_ELMT_SZ)
	#define MCAN0_RX_BUF_DATA_SIZE  (5u)
#elif (48 == MCAN0_RX_BUF_ELMT_SZ)
	#define MCAN0_RX_BUF_DATA_SIZE  (6u)
#elif (64 == MCAN0_RX_BUF_ELMT_SZ)
	#define MCAN0_RX_BUF_DATA_SIZE  (7u)
#else
	#error "Invalid CAN0 RX BUFFER ELEMENT SIZE"
#endif

#if   (8 == MCAN0_TX_BUF_ELMT_SZ)
	#define MCAN0_TX_BUF_DATA_SIZE  (0u)
#elif (12 == MCAN0_TX_BUF_ELMT_SZ)
	#define MCAN0_TX_BUF_DATA_SIZE  (1u)
#elif (16 == MCAN0_TX_BUF_ELMT_SZ)
	#define MCAN0_TX_BUF_DATA_SIZE  (2u)
#elif (20 == MCAN0_TX_BUF_ELMT_SZ)
	#define MCAN0_TX_BUF_DATA_SIZE  (3u)
#elif (24 == MCAN0_TX_BUF_ELMT_SZ)
	#define MCAN0_TX_BUF_DATA_SIZE  (4u)
#elif (32 == MCAN0_TX_BUF_ELMT_SZ)
	#define MCAN0_TX_BUF_DATA_SIZE  (5u)
#elif (48 == MCAN0_TX_BUF_ELMT_SZ)
	#define MCAN0_TX_BUF_DATA_SIZE  (6u)
#elif (64 == MCAN0_TX_BUF_ELMT_SZ)
	#define MCAN0_TX_BUF_DATA_SIZE  (7u)
#else
	#error "Invalid CAN0 TX BUFFER ELEMENT SIZE"
#endif

/* validate CAN1 entries */
#if (MCAN1_TSEG1 > 63)
	#error "Invalid CAN1 TSEG1"
#endif
#if (MCAN1_TSEG2 > 15)
	#error "Invalid CAN1 TSEG2"
#endif
#if (MCAN1_SJW > 15)
	#error "Invalid CAN1 SJW"
#endif
#if (MCAN1_FTSEG1 > 15)
	#error "Invalid CAN1 FTSEG1"
#endif
#if (MCAN1_FTSEG2 > 7)
	#error "Invalid CAN1 FTSEG2"
#endif
#if (MCAN1_FSJW > 3)
	#error "Invalid CAN1 FSJW"
#endif

#if (MCAN1_NMBR_STD_FLTS > 128)
	#error "Invalid CAN1 # of Standard Filters"
#endif
#if (MCAN1_NMBR_EXT_FLTS > 64)
	#error "Invalid CAN1 # of Extended Filters"
#endif
#if (MCAN1_NMBR_RX_FIFO0_ELMTS > 64)
	#error "Invalid CAN1 # RX FIFO 0 ELEMENTS"
#endif
#if (MCAN1_NMBR_RX_FIFO1_ELMTS > 64)
	#error "Invalid CAN1 # RX FIFO 0 ELEMENTS"
#endif
#if (MCAN1_NMBR_RX_DED_BUF_ELMTS > 64)
	#error "Invalid CAN1 # RX BUFFER ELEMENTS"
#endif
#if (MCAN1_NMBR_TX_EVT_FIFO_ELMTS > 32)
	#error "Invalid CAN1 # TX EVENT FIFO ELEMENTS"
#endif
#if ((MCAN1_NMBR_TX_DED_BUF_ELMTS + MCAN1_NMBR_TX_FIFO_Q_ELMTS)  > 32)
	#error "Invalid CAN1 # TX BUFFER ELEMENTS"
#endif

#if   (8 == MCAN1_RX_FIFO0_ELMT_SZ)
	#define MCAN1_RX_FIFO0_DATA_SIZE  (0u)
#elif (12 == MCAN1_RX_FIFO0_ELMT_SZ)
	#define MCAN1_RX_FIFO0_DATA_SIZE  (1u)
#elif (16 == MCAN1_RX_FIFO0_ELMT_SZ)
	#define MCAN1_RX_FIFO0_DATA_SIZE  (2u)
#elif (20 == MCAN1_RX_FIFO0_ELMT_SZ)
	#define MCAN1_RX_FIFO0_DATA_SIZE  (3u)
#elif (24 == MCAN1_RX_FIFO0_ELMT_SZ)
	#define MCAN1_RX_FIFO0_DATA_SIZE  (4u)
#elif (32 == MCAN1_RX_FIFO0_ELMT_SZ)
	#define MCAN1_RX_FIFO0_DATA_SIZE  (5u)
#elif (48 == MCAN1_RX_FIFO0_ELMT_SZ)
	#define MCAN1_RX_FIFO0_DATA_SIZE  (6u)
#elif (64 == MCAN1_RX_FIFO0_ELMT_SZ)
	#define MCAN1_RX_FIFO0_DATA_SIZE  (7u)
#else
	#error "Invalid CAN1 RX FIFO0 ELEMENT SIZE"
#endif

#if   (8 == MCAN1_RX_FIFO1_ELMT_SZ)
	#define MCAN1_RX_FIFO1_DATA_SIZE  (0u)
#elif (12 == MCAN1_RX_FIFO1_ELMT_SZ)
	#define MCAN1_RX_FIFO1_DATA_SIZE  (1u)
#elif (16 == MCAN1_RX_FIFO1_ELMT_SZ)
	#define MCAN1_RX_FIFO1_DATA_SIZE  (2u)
#elif (20 == MCAN1_RX_FIFO1_ELMT_SZ)
	#define MCAN1_RX_FIFO1_DATA_SIZE  (3u)
#elif (24 == MCAN1_RX_FIFO1_ELMT_SZ)
	#define MCAN1_RX_FIFO1_DATA_SIZE  (4u)
#elif (32 == MCAN1_RX_FIFO1_ELMT_SZ)
	#define MCAN1_RX_FIFO1_DATA_SIZE  (5u)
#elif (48 == MCAN1_RX_FIFO1_ELMT_SZ)
	#define MCAN1_RX_FIFO1_DATA_SIZE  (6u)
#elif (64 == MCAN1_RX_FIFO1_ELMT_SZ)
	#define MCAN1_RX_FIFO1_DATA_SIZE  (7u)
#else
	#error "Invalid CAN1 RX FIFO1 ELEMENT SIZE"
#endif

#if   (8 == MCAN1_RX_BUF_ELMT_SZ)
	#define MCAN1_RX_BUF_DATA_SIZE  (0u)
#elif (12 == MCAN1_RX_BUF_ELMT_SZ)
	#define MCAN1_RX_BUF_DATA_SIZE  (1u)
#elif (16 == MCAN1_RX_BUF_ELMT_SZ)
	#define MCAN1_RX_BUF_DATA_SIZE  (2u)
#elif (20 == MCAN1_RX_BUF_ELMT_SZ)
	#define MCAN1_RX_BUF_DATA_SIZE  (3u)
#elif (24 == MCAN1_RX_BUF_ELMT_SZ)
	#define MCAN1_RX_BUF_DATA_SIZE  (4u)
#elif (32 == MCAN1_RX_BUF_ELMT_SZ)
	#define MCAN1_RX_BUF_DATA_SIZE  (5u)
#elif (48 == MCAN1_RX_BUF_ELMT_SZ)
	#define MCAN1_RX_BUF_DATA_SIZE  (6u)
#elif (64 == MCAN1_RX_BUF_ELMT_SZ)
	#define MCAN1_RX_BUF_DATA_SIZE  (7u)
#else
	#error "Invalid CAN1 RX BUFFER ELEMENT SIZE"
#endif

#if   (8 == MCAN1_TX_BUF_ELMT_SZ)
	#define MCAN1_TX_BUF_DATA_SIZE  (0u)
#elif (12 == MCAN1_TX_BUF_ELMT_SZ)
	#define MCAN1_TX_BUF_DATA_SIZE  (1u)
#elif (16 == MCAN1_TX_BUF_ELMT_SZ)
	#define MCAN1_TX_BUF_DATA_SIZE  (2u)
#elif (20 == MCAN1_TX_BUF_ELMT_SZ)
	#define MCAN1_TX_BUF_DATA_SIZE  (3u)
#elif (24 == MCAN1_TX_BUF_ELMT_SZ)
	#define MCAN1_TX_BUF_DATA_SIZE  (4u)
#elif (32 == MCAN1_TX_BUF_ELMT_SZ)
	#define MCAN1_TX_BUF_DATA_SIZE  (5u)
#elif (48 == MCAN1_TX_BUF_ELMT_SZ)
	#define MCAN1_TX_BUF_DATA_SIZE  (6u)
#elif (64 == MCAN1_TX_BUF_ELMT_SZ)
	#define MCAN1_TX_BUF_DATA_SIZE  (7u)
#else
	#error "Invalid CAN1 TX BUFFER ELEMENT SIZE"
#endif

#define CAN_11_BIT_ID_MASK                 (0x7FF)
#define CAN_29_BIT_ID_MASK                 (0x1FFFFFFF)
#define ELMT_SIZE_MASK                (0x1F)
/* max element size is 18 words, fits in 5 bits */

#define BUFFER_XTD_MASK               (0x40000000)
#define BUFFER_EXT_ID_MASK            (0x1FFFFFFF)
#define BUFFER_STD_ID_MASK            (0x1FFC0000)
#define BUFFER_DLC_MASK               (0x000F0000)
#define BUFFER_RXTS_MASK              (0x0000FFFF)

#define STD_FILT_SFT_MASK             (3U << 30)
#define STD_FILT_SFT_RANGE            (0U << 30)
#define STD_FILT_SFT_DUAL             (1U << 30)
#define STD_FILT_SFT_CLASSIC          (2U << 30)
#define STD_FILT_SFEC_MASK            (7U << 27)
#define STD_FILT_SFEC_DISABLE         (0U << 27)
#define STD_FILT_SFEC_FIFO0           (1U << 27)
#define STD_FILT_SFEC_FIFO1           (2U << 27)
#define STD_FILT_SFEC_REJECT          (3U << 27)
#define STD_FILT_SFEC_PRIORITY        (4U << 27)
#define STD_FILT_SFEC_PRIORITY_FIFO0  (5U << 27)
#define STD_FILT_SFEC_PRIORITY_FIFO1  (6U << 27)
#define STD_FILT_SFEC_BUFFER          (7U << 27)
#define STD_FILT_SFID1_MASK           (0x03FFU << 16)
#define STD_FILT_SFID2_MASK           (0x3FFU << 0)
#define STD_FILT_SFID2_RX_BUFFER      (0U << 9)
#define STD_FILT_SFID2_DEBUG_A        (1U << 9)
#define STD_FILT_SFID2_DEBUG_B        (2U << 9)
#define STD_FILT_SFID2_DEBUG_C        (3U << 9)
#define STD_FILT_SFID2_BUFFER(nmbr)   (nmbr & 0x3F)

#define EXT_FILT_EFEC_MASK            (7U << 29)
#define EXT_FILT_EFEC_DISABLE         (0U << 29)
#define EXT_FILT_EFEC_FIFO0           (1U << 29)
#define EXT_FILT_EFEC_FIFO1           (2U << 29)
#define EXT_FILT_EFEC_REJECT          (3U << 29)
#define EXT_FILT_EFEC_PRIORITY        (4U << 29)
#define EXT_FILT_EFEC_PRIORITY_FIFO0  (5U << 29)
#define EXT_FILT_EFEC_PRIORITY_FIFO1  (6U << 29)
#define EXT_FILT_EFEC_BUFFER          (7U << 29)
#define EXT_FILT_EFID1_MASK           (0x1FFFFFFF)
#define EXT_FILT_EFT_MASK             (3U << 30)
#define EXT_FILT_EFT_RANGE            (0U << 30)
#define EXT_FILT_EFT_DUAL             (1U << 30)
#define EXT_FILT_EFT_CLASSIC          (2U << 30)
#define EXT_FILT_EFT_RANGE_NO_XIDAM   (3U << 30)
#define EXT_FILT_EFID2_MASK           (0x1FFFFFFF)
#define EXT_FILT_EFID2_RX_BUFFER      (0U << 9)
#define EXT_FILT_EFID2_DEBUG_A        (1U << 9)
#define EXT_FILT_EFID2_DEBUG_B        (2U << 9)
#define EXT_FILT_EFID2_DEBUG_C        (3U << 9)
#define EXT_FILT_EFID2_BUFFER(nmbr)   (nmbr & 0x3F)


/*---------------------------------------------------------------------------
 *      Internal variables
 *---------------------------------------------------------------------------*/

#ifndef __rtems__
static const Pin pinsMcan0[] =  {PIN_MCAN0_TXD, PIN_MCAN0_RXD };
static const Pin pinsMcan1[] =  {PIN_MCAN1_TXD, PIN_MCAN1_RXD };
#endif /* __rtems__ */

static uint32_t can0MsgRam[MCAN0_STD_FLTS_WRDS +
						   MCAN0_EXT_FLTS_WRDS +
						   MCAN0_RX_FIFO0_WRDS +
						   MCAN0_RX_FIFO1_WRDS +
						   MCAN0_RX_DED_BUFS_WRDS +
						   MCAN0_TX_EVT_FIFO_WRDS +
						   MCAN0_TX_DED_BUF_WRDS +
						   MCAN0_TX_FIFO_Q_WRDS];

static uint32_t can1MsgRam[MCAN1_STD_FLTS_WRDS +
						   MCAN1_EXT_FLTS_WRDS +
						   MCAN1_RX_FIFO0_WRDS +
						   MCAN1_RX_FIFO1_WRDS +
						   MCAN1_RX_DED_BUFS_WRDS +
						   MCAN1_TX_EVT_FIFO_WRDS +
						   MCAN1_TX_DED_BUF_WRDS +
						   MCAN1_TX_FIFO_Q_WRDS];

static const uint8_t dlcToMsgLength[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64 };

const MCan_ConfigType mcan0Config = {
	MCAN0,
	MCAN_BTP_BRP(MCAN0_BRP) | MCAN_BTP_TSEG1(MCAN0_TSEG1) |
	MCAN_BTP_TSEG2(MCAN0_TSEG2) | MCAN_BTP_SJW(MCAN0_SJW),
	MCAN_FBTP_FBRP(MCAN0_FBRP) | MCAN_FBTP_FTSEG1(MCAN0_FTSEG1) |
	MCAN_FBTP_FTSEG2(MCAN0_FTSEG2) | MCAN_FBTP_FSJW(MCAN0_FSJW),
	MCAN0_NMBR_STD_FLTS,
	MCAN0_NMBR_EXT_FLTS,
	MCAN0_NMBR_RX_FIFO0_ELMTS,
	MCAN0_NMBR_RX_FIFO1_ELMTS,
	MCAN0_NMBR_RX_DED_BUF_ELMTS,
	MCAN0_NMBR_TX_EVT_FIFO_ELMTS,
	MCAN0_NMBR_TX_DED_BUF_ELMTS,
	MCAN0_NMBR_TX_FIFO_Q_ELMTS,
	(MCAN0_RX_FIFO0_DATA_SIZE << 29) | ((MCAN0_RX_FIFO0_ELMT_SZ / 4) + 2),
	/* element size in WORDS */
	(MCAN0_RX_FIFO1_DATA_SIZE << 29) | ((MCAN0_RX_FIFO1_ELMT_SZ / 4) + 2),
	/* element size in WORDS */
	(MCAN0_RX_BUF_DATA_SIZE << 29) | ((MCAN0_RX_BUF_ELMT_SZ / 4) + 2),
	/* element size in WORDS */
	(MCAN0_TX_BUF_DATA_SIZE << 29) | ((MCAN0_TX_BUF_ELMT_SZ / 4) + 2),
	/* element size in WORDS */
	{
		&can0MsgRam[0],
		&can0MsgRam[MCAN0_STD_FLTS_WRDS],
		&can0MsgRam[MCAN0_STD_FLTS_WRDS + MCAN0_EXT_FLTS_WRDS],
		&can0MsgRam[MCAN0_STD_FLTS_WRDS + MCAN0_EXT_FLTS_WRDS + MCAN0_RX_FIFO0_WRDS],
		&can0MsgRam[MCAN0_STD_FLTS_WRDS + MCAN0_EXT_FLTS_WRDS + MCAN0_RX_FIFO0_WRDS +
		MCAN0_RX_FIFO1_WRDS],
		&can0MsgRam[MCAN0_STD_FLTS_WRDS + MCAN0_EXT_FLTS_WRDS + MCAN0_RX_FIFO0_WRDS +
		MCAN0_RX_FIFO1_WRDS + MCAN0_RX_DED_BUFS_WRDS],
		&can0MsgRam[MCAN0_STD_FLTS_WRDS + MCAN0_EXT_FLTS_WRDS + MCAN0_RX_FIFO0_WRDS +
		MCAN0_RX_FIFO1_WRDS + MCAN0_RX_DED_BUFS_WRDS + MCAN0_TX_EVT_FIFO_WRDS],
		&can0MsgRam[MCAN0_STD_FLTS_WRDS + MCAN0_EXT_FLTS_WRDS + MCAN0_RX_FIFO0_WRDS +
		MCAN0_RX_FIFO1_WRDS + MCAN0_RX_DED_BUFS_WRDS + MCAN0_TX_EVT_FIFO_WRDS +
		MCAN0_TX_DED_BUF_WRDS]
	},
};

const MCan_ConfigType mcan1Config = {
	MCAN1,
	MCAN_BTP_BRP(MCAN1_BRP) | MCAN_BTP_TSEG1(MCAN1_TSEG1) |
	MCAN_BTP_TSEG2(MCAN1_TSEG2) | MCAN_BTP_SJW(MCAN1_SJW),
	MCAN_FBTP_FBRP(MCAN1_FBRP) | MCAN_FBTP_FTSEG1(MCAN1_FTSEG1) |
	MCAN_FBTP_FTSEG2(MCAN1_FTSEG2) | MCAN_FBTP_FSJW(MCAN1_FSJW),
	MCAN1_NMBR_STD_FLTS,
	MCAN1_NMBR_EXT_FLTS,
	MCAN1_NMBR_RX_FIFO0_ELMTS,
	MCAN1_NMBR_RX_FIFO1_ELMTS,
	MCAN0_NMBR_RX_DED_BUF_ELMTS,
	MCAN1_NMBR_TX_EVT_FIFO_ELMTS,
	MCAN1_NMBR_TX_DED_BUF_ELMTS,
	MCAN1_NMBR_TX_FIFO_Q_ELMTS,
	(MCAN1_RX_FIFO0_DATA_SIZE << 29) | ((MCAN1_RX_FIFO0_ELMT_SZ / 4) + 2),
	/* element size in WORDS */
	(MCAN1_RX_FIFO1_DATA_SIZE << 29) | ((MCAN1_RX_FIFO1_ELMT_SZ / 4) + 2),
	/* element size in WORDS */
	(MCAN1_RX_BUF_DATA_SIZE << 29) | ((MCAN1_RX_BUF_ELMT_SZ / 4) + 2),
	/* element size in WORDS */
	(MCAN1_TX_BUF_DATA_SIZE << 29) | ((MCAN1_TX_BUF_ELMT_SZ / 4) + 2),
	/* element size in WORDS */
	{
		&can1MsgRam[0],
		&can1MsgRam[MCAN1_STD_FLTS_WRDS],
		&can1MsgRam[MCAN1_STD_FLTS_WRDS + MCAN1_EXT_FLTS_WRDS],
		&can1MsgRam[MCAN1_STD_FLTS_WRDS + MCAN1_EXT_FLTS_WRDS + MCAN1_RX_FIFO0_WRDS],
		&can1MsgRam[MCAN1_STD_FLTS_WRDS + MCAN1_EXT_FLTS_WRDS + MCAN1_RX_FIFO0_WRDS
		+ MCAN1_RX_FIFO1_WRDS],
		&can1MsgRam[MCAN1_STD_FLTS_WRDS + MCAN1_EXT_FLTS_WRDS + MCAN1_RX_FIFO0_WRDS
		+ MCAN1_RX_FIFO1_WRDS + MCAN1_RX_DED_BUFS_WRDS],
		&can1MsgRam[MCAN1_STD_FLTS_WRDS + MCAN1_EXT_FLTS_WRDS + MCAN1_RX_FIFO0_WRDS
		+ MCAN1_RX_FIFO1_WRDS + MCAN1_RX_DED_BUFS_WRDS + MCAN1_TX_EVT_FIFO_WRDS],
		&can1MsgRam[MCAN1_STD_FLTS_WRDS + MCAN1_EXT_FLTS_WRDS + MCAN1_RX_FIFO0_WRDS
		+ MCAN1_RX_FIFO1_WRDS + MCAN1_RX_DED_BUFS_WRDS + MCAN1_TX_EVT_FIFO_WRDS
		+ MCAN1_TX_DED_BUF_WRDS]
	},
};


/*---------------------------------------------------------------------------
 *      Exported Functions
 *---------------------------------------------------------------------------*/
/**
* \brief Initializes the MCAN hardware for giving peripheral.
* Default: Mixed mode TX Buffer + FIFO.
*
* \param mcanConfig  Pointer to a MCAN instance.
*/
void MCAN_Init(const MCan_ConfigType *mcanConfig)
{
	Mcan       *mcan = mcanConfig->pMCan;
	uint32_t    regVal32;
	uint32_t   *pMsgRam;
	uint32_t    cntr;
	IRQn_Type   mCanLine0Irq;

	/* Both MCAN controllers use programmable clock 5 to derive bit rate */
	// select MCK divided by 1 as programmable clock 5 output
	PMC->PMC_PCK[5] = PMC_PCK_PRES(MCAN_PROG_CLK_PRESCALER - 1) |
					  MCAN_PROG_CLK_SELECT;
	PMC->PMC_SCER = PMC_SCER_PCK5;

	if (MCAN0 ==  mcan) {
#ifndef __rtems__
		PIO_Configure(pinsMcan0, PIO_LISTSIZE(pinsMcan0));
#endif /* __rtems__ */
		// Enable MCAN peripheral clock
		PMC_EnablePeripheral(ID_MCAN0);
		// Configure Message RAM Base Address
		regVal32 = MATRIX->CCFG_CAN0 & 0x000001FF;
		MATRIX->CCFG_CAN0 = regVal32 |
							((uint32_t) mcanConfig->msgRam.pStdFilts & 0xFFFF0000);
		mCanLine0Irq = MCAN0_IRQn;
	} else if (MCAN1 ==  mcan) {
#ifndef __rtems__
		PIO_Configure(pinsMcan1, PIO_LISTSIZE(pinsMcan1));
#endif /* __rtems__ */
		// Enable MCAN peripheral clock
		PMC_EnablePeripheral(ID_MCAN1);
		// Configure Message RAM Base Address
		regVal32 = MATRIX->CCFG_SYSIO & 0x0000FFFF;
		MATRIX->CCFG_SYSIO = regVal32 | ((uint32_t) mcanConfig->msgRam.pStdFilts &
										  0xFFFF0000);
		mCanLine0Irq = MCAN1_IRQn;
	} else
		return;

	/* Indicates Initialization state */
	mcan->MCAN_CCCR = MCAN_CCCR_INIT_ENABLED;

	do { regVal32 = mcan->MCAN_CCCR; }
	while (0u == (regVal32 & MCAN_CCCR_INIT_ENABLED));

	/* Enable writing to configuration registers */
	mcan->MCAN_CCCR = MCAN_CCCR_INIT_ENABLED | MCAN_CCCR_CCE_CONFIGURABLE;

	/* Global Filter Configuration: Reject remote frames, reject non-matching frames */
	mcan->MCAN_GFC = MCAN_GFC_RRFE_REJECT | MCAN_GFC_RRFS_REJECT
					 | MCAN_GFC_ANFE(2) | MCAN_GFC_ANFS(2);

	// Extended ID Filter AND mask
	mcan->MCAN_XIDAM = 0x1FFFFFFF;

	/* Interrupt configuration - leave initialization with all interrupts off */
	// Disable all interrupts
	mcan->MCAN_IE =  0;
	mcan->MCAN_TXBTIE = 0x00000000;
	// All interrupts directed to Line 0
	mcan->MCAN_ILS =  0x00000000;
	// Disable both interrupt LINE 0 & LINE 1
	mcan->MCAN_ILE = 0x00;
	// Clear all interrupt flags
	mcan->MCAN_IR = 0xFFCFFFFF;
	/* Enable NVIC - but no interrupts will happen since all sources are
	    disabled in MCAN_IE */
	NVIC_ClearPendingIRQ(mCanLine0Irq);
	NVIC_EnableIRQ(mCanLine0Irq);
	NVIC_ClearPendingIRQ((IRQn_Type) (mCanLine0Irq + 1));
	NVIC_EnableIRQ((IRQn_Type) (mCanLine0Irq + 1));

	/* Configure CAN bit timing */
	mcan->MCAN_BTP = mcanConfig->bitTiming;
	mcan->MCAN_FBTP = mcanConfig->fastBitTiming;

	/* Configure message RAM starting addresses & sizes */
	mcan->MCAN_SIDFC = MAILBOX_ADDRESS((uint32_t) mcanConfig->msgRam.pStdFilts)
					   | MCAN_SIDFC_LSS(mcanConfig->nmbrStdFilts);
	mcan->MCAN_XIDFC = MAILBOX_ADDRESS((uint32_t) mcanConfig->msgRam.pExtFilts)
					   | MCAN_XIDFC_LSE(mcanConfig->nmbrExtFilts);
	mcan->MCAN_RXF0C = MAILBOX_ADDRESS((uint32_t) mcanConfig->msgRam.pRxFifo0)
					   | MCAN_RXF0C_F0S(mcanConfig->nmbrFifo0Elmts);
	// watermark interrupt off, blocking mode
	mcan->MCAN_RXF1C = MAILBOX_ADDRESS((uint32_t) mcanConfig->msgRam.pRxFifo1)
					   | MCAN_RXF1C_F1S(mcanConfig->nmbrFifo1Elmts);
	// watermark interrupt off, blocking mode
	mcan->MCAN_RXBC = MAILBOX_ADDRESS((uint32_t) mcanConfig->msgRam.pRxDedBuf);
	mcan->MCAN_TXEFC = MAILBOX_ADDRESS((uint32_t) mcanConfig->msgRam.pTxEvtFifo)
					   | MCAN_TXEFC_EFS(mcanConfig->nmbrTxEvtFifoElmts);
	// watermark interrupt off
	mcan->MCAN_TXBC = MAILBOX_ADDRESS((uint32_t) mcanConfig->msgRam.pTxDedBuf)
					  | MCAN_TXBC_NDTB(mcanConfig->nmbrTxDedBufElmts)
					  | MCAN_TXBC_TFQS(mcanConfig->nmbrTxFifoQElmts);
	mcan->MCAN_RXESC = ((mcanConfig->rxBufElmtSize >> (29 - MCAN_RXESC_RBDS_Pos)) &
						MCAN_RXESC_RBDS_Msk) |
					   ((mcanConfig->rxFifo1ElmtSize >> (29 - MCAN_RXESC_F1DS_Pos)) &
						MCAN_RXESC_F1DS_Msk) |
					   ((mcanConfig->rxFifo0ElmtSize >> (29 - MCAN_RXESC_F0DS_Pos)) &
						MCAN_RXESC_F0DS_Msk);
	mcan->MCAN_TXESC = ((mcanConfig->txBufElmtSize >> (29 - MCAN_TXESC_TBDS_Pos)) &
						MCAN_TXESC_TBDS_Msk);

	/* Configure Message Filters */
	// ...Disable all standard filters
	pMsgRam = mcanConfig->msgRam.pStdFilts;
	cntr = mcanConfig->nmbrStdFilts;

	while (cntr > 0) {
		*pMsgRam++ = STD_FILT_SFEC_DISABLE;
		cntr--;
	}

	// ...Disable all extended filters
	pMsgRam = mcanConfig->msgRam.pExtFilts;
	cntr = mcanConfig->nmbrExtFilts;

	while (cntr > 0) {
		*pMsgRam = EXT_FILT_EFEC_DISABLE;
		pMsgRam = pMsgRam + 2;
		cntr--;
	}

	mcan->MCAN_NDAT1 = 0xFFFFFFFF;  // clear new (rx) data flags
	mcan->MCAN_NDAT2 = 0xFFFFFFFF;  // clear new (rx) data flags

	regVal32 =  mcan->MCAN_CCCR & ~(MCAN_CCCR_CME_Msk | MCAN_CCCR_CMR_Msk);
	mcan->MCAN_CCCR = regVal32 | MCAN_CCCR_CME_ISO11898_1;
	mcan->MCAN_CCCR = regVal32 | (MCAN_CCCR_CMR_ISO11898_1 |
								  MCAN_CCCR_CME_ISO11898_1);

	__DSB();
	__ISB();
}

/**
 * \brief Enables a FUTURE switch to FD mode (tx & rx payloads up to 64 bytes)
 * but transmits WITHOUT bit rate switching
 * INIT must be set - so this should be called between MCAN_Init() and
 * MCAN_Enable()
 * \param mcanConfig  Pointer to a MCAN instance.
 */
void MCAN_InitFdEnable(const MCan_ConfigType *mcanConfig)
{
	Mcan      *mcan = mcanConfig->pMCan;
	uint32_t   regVal32;

	regVal32 =  mcan->MCAN_CCCR & ~MCAN_CCCR_CME_Msk;
	mcan->MCAN_CCCR = regVal32 | MCAN_CCCR_CME(1);
}

/**
 * \brief Enables a FUTURE switch to FD mode (tx & rx payloads up to 64 bytes) and transmits
 * WITH bit rate switching
 * INIT must be set - so this should be called between MCAN_Init() and MCAN_Enable()
 * \param mcanConfig  Pointer to a MCAN instance.
 */
void MCAN_InitFdBitRateSwitchEnable(const MCan_ConfigType *mcanConfig)
{
	Mcan      *mcan = mcanConfig->pMCan;
	uint32_t   regVal32;

	regVal32 =  mcan->MCAN_CCCR & ~MCAN_CCCR_CME_Msk;
	mcan->MCAN_CCCR = regVal32 | MCAN_CCCR_CME(2);
}

/**
 * \brief Initializes the MCAN in loop back mode.
 * INIT must be set - so this should be called between MCAN_Init() and
 * MCAN_Enable()
 * \param mcanConfig  Pointer to a MCAN instance.
 */
void MCAN_InitLoopback(const MCan_ConfigType *mcanConfig)
{
	Mcan *mcan = mcanConfig->pMCan;

	mcan->MCAN_CCCR |= MCAN_CCCR_TEST_ENABLED;
	//mcan->MCAN_CCCR |= MCAN_CCCR_MON_ENABLED;  // for internal loop back
	mcan->MCAN_TEST |= MCAN_TEST_LBCK_ENABLED;
}

/**
 * \brief Initializes MCAN queue for TX
 * INIT must be set - so this should be called between MCAN_Init() and
 * MCAN_Enable()
 * \param mcanConfig  Pointer to a MCAN instance.
 */
void MCAN_InitTxQueue(const MCan_ConfigType *mcanConfig)
{
	Mcan *mcan = mcanConfig->pMCan;
	mcan->MCAN_TXBC |= MCAN_TXBC_TFQM;
}

/**
 * \brief Enable MCAN peripheral.
 * INIT must be set - so this should be called between MCAN_Init()
 * \param mcanConfig  Pointer to a MCAN instance.
 */
void MCAN_Enable(const MCan_ConfigType *mcanConfig)
{
	Mcan *mcan = mcanConfig->pMCan;
	mcan->MCAN_CCCR &= ~MCAN_CCCR_INIT_ENABLED;
}

/**
 * \brief Requests switch to Iso11898-1 (standard / classic) mode (tx & rx
 * payloads up to 8 bytes).
 * \param mcanConfig  Pointer to a MCAN instance.
 */
void MCAN_RequestIso11898_1(const MCan_ConfigType *mcanConfig)
{
	Mcan      *mcan = mcanConfig->pMCan;
	uint32_t   regVal32;

	regVal32 =  mcan->MCAN_CCCR & ~MCAN_CCCR_CMR_Msk;
	mcan->MCAN_CCCR = regVal32 | MCAN_CCCR_CMR_ISO11898_1;

	while ((mcan->MCAN_CCCR & (MCAN_CCCR_FDBS | MCAN_CCCR_FDO)) != 0)
	{ /* wait */ }
}

/**
 * \brief Requests switch to FD mode (tx & rx payloads up to 64 bytes) but
 * transmits WITHOUT bit
 * rate switching. requested mode should have been enabled at initialization
 * \param mcanConfig  Pointer to a MCAN instance.
 */
void MCAN_RequestFd(const MCan_ConfigType *mcanConfig)
{
	Mcan      *mcan = mcanConfig->pMCan;
	uint32_t   regVal32;

	if ((mcan->MCAN_CCCR & MCAN_CCCR_CME_Msk) == MCAN_CCCR_CME(1)) {
		regVal32 =  mcan->MCAN_CCCR & ~MCAN_CCCR_CMR_Msk;
		mcan->MCAN_CCCR = regVal32 | MCAN_CCCR_CMR_FD;

		while ((mcan->MCAN_CCCR & MCAN_CCCR_FDO) == 0) { /* wait */ }
	}
}

/**
 * \brief Request switch to FD mode (tx & rx payloads up to 64 bytes) and
 * transmits WITH bit rate switching.
 * requested mode should have been enabled at initialization
 * \param mcanConfig  Pointer to a MCAN instance.
 */
void MCAN_RequestFdBitRateSwitch(const MCan_ConfigType *mcanConfig)
{
	Mcan      *mcan = mcanConfig->pMCan;
	uint32_t   regVal32;

	if ((mcan->MCAN_CCCR & MCAN_CCCR_CME_Msk) == MCAN_CCCR_CME(2)) {
		regVal32 =  mcan->MCAN_CCCR & ~MCAN_CCCR_CMR_Msk;
		mcan->MCAN_CCCR = regVal32 | MCAN_CCCR_CMR_FD_BITRATE_SWITCH;

		while ((mcan->MCAN_CCCR & (MCAN_CCCR_FDBS | MCAN_CCCR_FDO)) !=
				(MCAN_CCCR_FDBS | MCAN_CCCR_FDO)) { /* wait */ }
	}
}

/**
 * \brief Switch on loop back mode.
 * TEST must be set in MCAN_CCCR - e.g. by a prior call to MCAN_InitLoopback()
 * \param mcanConfig  Pointer to a MCAN instance.
 */
void MCAN_LoopbackOn(const MCan_ConfigType *mcanConfig)
{
	Mcan *mcan = mcanConfig->pMCan;
	mcan->MCAN_TEST |= MCAN_TEST_LBCK_ENABLED;
}

/**
 * \brief Switch off loop back mode.
 * \param mcanConfig  Pointer to a MCAN instance.
 */
void MCAN_LoopbackOff(const MCan_ConfigType *mcanConfig)
{
	Mcan *mcan = mcanConfig->pMCan;
	mcan->MCAN_TEST &= ~MCAN_TEST_LBCK_ENABLED;
}

/**
 * \brief Enable message line and message stored to Dedicated Receive Buffer
 * Interrupt Line.
 * \param mcanConfig  Pointer to a MCAN instance.
 * \param line  Message line.
 */
void MCAN_IEnableMessageStoredToRxDedBuffer(const MCan_ConfigType *mcanConfig,
		MCan_IntrLineType line)
{
	Mcan *mcan = mcanConfig->pMCan;

	if (line == CAN_INTR_LINE_0) {
		mcan->MCAN_ILS &= ~MCAN_ILS_DRXL;
		mcan->MCAN_ILE |= MCAN_ILE_EINT0;
	} else  {
		// Interrupt Line 1
		mcan->MCAN_ILS |= MCAN_ILS_DRXL;
		mcan->MCAN_ILE |= MCAN_ILE_EINT1;
	}

	mcan->MCAN_IR = MCAN_IR_DRX;  // clear previous flag
	mcan->MCAN_IE |= MCAN_IE_DRXE;  // enable it
}

/**
 * \brief Configures a Dedicated TX Buffer.
 * \param mcanConfig  Pointer to a MCAN instance.
 * \param buffer  Pointer to buffer.
 * \param id  Message ID.
 * \param idType  Type of ID
 * \param dlc  Type of dlc.
 */
uint8_t   *MCAN_ConfigTxDedBuffer(const MCan_ConfigType *mcanConfig,
								   uint8_t buffer, uint32_t id, MCan_IdType idType, MCan_DlcType dlc)
{
	Mcan *mcan = mcanConfig->pMCan;
	uint32_t *pThisTxBuf = 0;

	if (buffer < mcanConfig->nmbrTxDedBufElmts) {
		pThisTxBuf = mcanConfig->msgRam.pTxDedBuf + (buffer *
					 (mcanConfig->txBufElmtSize & ELMT_SIZE_MASK));

		if (idType == CAN_STD_ID)
			*pThisTxBuf++ = ((id << 18) & (CAN_11_BIT_ID_MASK << 18));
		else
			*pThisTxBuf++ = BUFFER_XTD_MASK | (id & CAN_29_BIT_ID_MASK);

		*pThisTxBuf++ = (uint32_t) dlc << 16;
		/* enable transmit from buffer to set TC interrupt bit in IR, but
		interrupt will not happen unless TC interrupt is enabled*/
		mcan->MCAN_TXBTIE = (1 << buffer);
	}

	return (uint8_t *) pThisTxBuf;  // now it points to the data field
}

/**
 * \brief Send Tx buffer.
 * \param mcanConfig  Pointer to a MCAN instance.
 * \param buffer  Pointer to buffer.
 */
void MCAN_SendTxDedBuffer(const MCan_ConfigType *mcanConfig, uint8_t buffer)
{
	Mcan *mcan = mcanConfig->pMCan;

	if (buffer < mcanConfig->nmbrTxDedBufElmts)
		mcan->MCAN_TXBAR = (1 << buffer);
}

/**
 * \brief Adds Message to TX Fifo / Queue
 * \param mcanConfig  Pointer to a MCAN instance.
 * \param id  Message ID.
 * \param idType  Type of ID
 * \param dlc  Type of dlc.
 * \param data  Pointer to data.
 */
uint32_t MCAN_AddToTxFifoQ(const MCan_ConfigType *mcanConfig,
							uint32_t id, MCan_IdType idType, MCan_DlcType dlc, uint8_t *data)
{
	Mcan *mcan = mcanConfig->pMCan;
	uint32_t   putIdx = 255;
	uint32_t *pThisTxBuf = 0;
	uint8_t   *pTxData;
	uint8_t    msgLength;
	uint8_t    cnt;

	// Configured for FifoQ and FifoQ not full?
	if ((mcanConfig->nmbrTxFifoQElmts > 0) &&
		((mcan->MCAN_TXFQS & MCAN_TXFQS_TFQF) == 0)) {
		putIdx = (mcan->MCAN_TXFQS & MCAN_TXFQS_TFQPI_Msk) >> MCAN_TXFQS_TFQPI_Pos;
		pThisTxBuf = mcanConfig->msgRam.pTxDedBuf + (putIdx *
					 (mcanConfig->txBufElmtSize & ELMT_SIZE_MASK));

		if (idType == CAN_STD_ID)
			*pThisTxBuf++ = ((id << 18) & (CAN_11_BIT_ID_MASK << 18));
		else
			*pThisTxBuf++ = BUFFER_XTD_MASK | (id & CAN_29_BIT_ID_MASK);

		*pThisTxBuf++ = (uint32_t) dlc << 16;
		pTxData = (uint8_t *) pThisTxBuf;
		msgLength = dlcToMsgLength[dlc];

		for (cnt = 0; cnt < msgLength; cnt++)
			*pTxData++ = *data++;

		/* enable transmit from buffer to set TC interrupt bit in IR, but
		interrupt will not happen unless TC interrupt is enabled */
		mcan->MCAN_TXBTIE = (1 << putIdx);
		// request to send
		mcan->MCAN_TXBAR = (1 << putIdx);
	}

	return putIdx;  // now it points to the data field
}

/**
 * \brief Check if data transmitted from buffer/fifo/queue
 * \param mcanConfig  Pointer to a MCAN instance.
 * \param buffer  Pointer to data buffer.
 */
uint8_t MCAN_IsBufferTxd(const MCan_ConfigType *mcanConfig, uint8_t buffer)
{
	Mcan *mcan = mcanConfig->pMCan;

	return (mcan->MCAN_TXBTO & (1 << buffer));
}

/**
 * \brief Configure RX Buffer Filter
 * ID must match exactly for a RX Buffer Filter
 * \param mcanConfig  Pointer to a MCAN instance.
 * \param buffer  Pointer to data buffer.
 * \param filter  data of filter.
 * \param idType  Type of ID
 */
void MCAN_ConfigRxBufferFilter(const MCan_ConfigType *mcanConfig,
								uint32_t buffer, uint32_t filter, uint32_t id, MCan_IdType idType)
{
	uint32_t *pThisRxFilt = 0;

	if (buffer < mcanConfig->nmbrRxDedBufElmts) {
		if (idType == CAN_STD_ID) {
			if ((filter < mcanConfig->nmbrStdFilts)
				&& (id <= CAN_11_BIT_ID_MASK)) {
				pThisRxFilt = mcanConfig->msgRam.pStdFilts + filter;
				// 1 word per filter
				*pThisRxFilt = STD_FILT_SFEC_BUFFER | (id << 16) |
							   STD_FILT_SFID2_RX_BUFFER | buffer;
			}
		} else {
			// extended ID
			if ((filter < mcanConfig->nmbrExtFilts) &&
				(id <= CAN_29_BIT_ID_MASK)) {
				pThisRxFilt = mcanConfig->msgRam.pExtFilts + (2 * filter);
				// 2 words per filter
				*pThisRxFilt++ = (uint32_t) EXT_FILT_EFEC_BUFFER | id;
				*pThisRxFilt = EXT_FILT_EFID2_RX_BUFFER | buffer;
			}
		}
	}
}

/**
 * \brief Configure Classic Filter
 * Classic Filters direct accepted messages to a FIFO & include both a ID and
 * a ID mask
 * \param mcanConfig  Pointer to a MCAN instance.
 * \param buffer  Pointer to data buffer.
 * \param fifo   fifo Number.
 * \param filter  data of filter.
 * \param idType  Type of ID
 * \param mask  Mask to be match
 */
void MCAN_ConfigRxClassicFilter(const MCan_ConfigType *mcanConfig,
								 MCan_FifoType fifo, uint8_t filter, uint32_t id,
								 MCan_IdType idType, uint32_t mask)
{
	uint32_t *pThisRxFilt = 0;
	uint32_t   filterTemp;

	if (idType == CAN_STD_ID) {
		if ((filter < mcanConfig->nmbrStdFilts) && (id <= CAN_11_BIT_ID_MASK)
			&& (mask <= CAN_11_BIT_ID_MASK)) {
			pThisRxFilt = mcanConfig->msgRam.pStdFilts + filter;
			// 1 word per filter
			filterTemp = (uint32_t) STD_FILT_SFT_CLASSIC | (id << 16) | mask;

			if (fifo == CAN_FIFO_0)
				*pThisRxFilt = STD_FILT_SFEC_FIFO0 | filterTemp;
			else if (fifo == CAN_FIFO_1)
				*pThisRxFilt = STD_FILT_SFEC_FIFO1 | filterTemp;
		}
	} else {
		// extended ID
		if ((filter < mcanConfig->nmbrExtFilts)
			&& (id <= CAN_29_BIT_ID_MASK)
			&& (mask <= CAN_29_BIT_ID_MASK)) {
			pThisRxFilt = mcanConfig->msgRam.pExtFilts + (2 * filter);

			// 2 words per filter
			if (fifo == CAN_FIFO_0)
				*pThisRxFilt++ = EXT_FILT_EFEC_FIFO0 | id;
			else if (fifo == CAN_FIFO_1)
				*pThisRxFilt++ = EXT_FILT_EFEC_FIFO1 | id;

			*pThisRxFilt = (uint32_t) EXT_FILT_EFT_CLASSIC | mask;
		}
	}
}

/**
 * \brief check if data received into buffer
 * \param mcanConfig  Pointer to a MCAN instance.
 * \param buffer  Pointer to data buffer.
 */
uint8_t MCAN_IsNewDataInRxDedBuffer(const MCan_ConfigType *mcanConfig,
									 uint8_t buffer)
{
	Mcan *mcan = mcanConfig->pMCan;

	if (buffer < 32)
		return (mcan->MCAN_NDAT1 & (1 << buffer));
	else if (buffer < 64)
		return (mcan->MCAN_NDAT1 & (1 << (buffer - 32)));
	else
		return 0;
}

/**
 * \brief Get Rx buffer
 * \param mcanConfig  Pointer to a MCAN instance.
 * \param buffer  Pointer to data buffer.
 * \param pRxMailbox  Pointer to rx Mailbox.
 */
void MCAN_GetRxDedBuffer(const MCan_ConfigType *mcanConfig,
						  uint8_t buffer, Mailbox64Type *pRxMailbox)
{
	Mcan      *mcan = mcanConfig->pMCan;
	uint32_t *pThisRxBuf = 0;
	uint32_t   tempRy;  // temp copy of RX buffer word
	uint32_t   dlc;
	uint8_t   *pRxData;
	uint8_t    idx;

	if (buffer < mcanConfig->nmbrRxDedBufElmts) {
		pThisRxBuf = mcanConfig->msgRam.pRxDedBuf
					 + (buffer * (mcanConfig->rxBufElmtSize & ELMT_SIZE_MASK));
		tempRy = *pThisRxBuf++;  // word R0 contains ID

		if (tempRy & BUFFER_XTD_MASK) {
			// extended ID?
			pRxMailbox->info.id = tempRy & BUFFER_EXT_ID_MASK;
		} else {
			// standard ID
			pRxMailbox->info.id = (tempRy & BUFFER_STD_ID_MASK) >> 18;
		}

		tempRy = *pThisRxBuf++;  // word R1 contains DLC & time stamp
		dlc = (tempRy & BUFFER_DLC_MASK) >> 16;
		pRxMailbox->info.length = dlcToMsgLength[dlc];
		pRxMailbox->info.timestamp = tempRy & BUFFER_RXTS_MASK;
		// copy the data from the buffer to the mailbox
		pRxData = (uint8_t *) pThisRxBuf;

		SCB_CleanDCache_by_Addr((uint32_t *)pRxData, pRxMailbox->info.length);
		SCB_CleanDCache_by_Addr((uint32_t *) & (pRxMailbox->data[0]),
								pRxMailbox->info.length);

		for (idx = 0; idx < pRxMailbox->info.length; idx++)
			pRxMailbox->data[idx] = *pRxData++;

		/* clear the new data flag for the buffer */

		if (buffer < 32)
			mcan->MCAN_NDAT1 = (1 << buffer);
		else
			mcan->MCAN_NDAT1 = (1 << (buffer - 32));

	}
}

/**
 * \brief Get from the receive FIFO and place in a application mailbox
 * \param mcanConfig  Pointer to a MCAN instance.
 * \param fifo  Fifo Number
 * \param pRxMailbox  Pointer to rx Mailbox.
 * \return: # of fifo entries at the start of the function
 *         0 -> FIFO was empty at start
 *         1 -> FIFO had 1 entry at start, but is empty at finish
 *         2 -> FIFO had 2 entries at start, has 1 entry at finish
 */
uint32_t MCAN_GetRxFifoBuffer(const MCan_ConfigType *mcanConfig,
							   MCan_FifoType fifo, Mailbox64Type *pRxMailbox)
{
	Mcan      *mcan = mcanConfig->pMCan;
	uint32_t *pThisRxBuf = 0;
	uint32_t   tempRy;  // temp copy of RX buffer word
	uint32_t   dlc;
	uint8_t   *pRxData;
	uint8_t    idx;
	uint32_t *fifo_ack_reg;
	uint32_t   get_index;
	uint32_t   fill_level;
	uint32_t   element_size;

	// default: fifo empty
	fill_level = 0;

	if (fifo == CAN_FIFO_0) {
		get_index = (mcan->MCAN_RXF0S & MCAN_RXF0S_F0GI_Msk) >> MCAN_RXF0S_F0GI_Pos;
		fill_level = (mcan->MCAN_RXF0S & MCAN_RXF0S_F0FL_Msk) >> MCAN_RXF0S_F0FL_Pos;
		pThisRxBuf = mcanConfig->msgRam.pRxFifo0;
		element_size = mcanConfig->rxFifo0ElmtSize & ELMT_SIZE_MASK;
		fifo_ack_reg = (uint32_t *) &mcan->MCAN_RXF0A;
	} else if (fifo == CAN_FIFO_1) {
		get_index = (mcan->MCAN_RXF1S & MCAN_RXF1S_F1GI_Msk) >> MCAN_RXF1S_F1GI_Pos;
		fill_level = (mcan->MCAN_RXF1S & MCAN_RXF1S_F1FL_Msk) >> MCAN_RXF1S_F1FL_Pos;
		pThisRxBuf = mcanConfig->msgRam.pRxFifo1;
		element_size = mcanConfig->rxFifo1ElmtSize & ELMT_SIZE_MASK;
		fifo_ack_reg = (uint32_t *) &mcan->MCAN_RXF1A;
	}

	if (fill_level > 0) {
		pThisRxBuf = pThisRxBuf + (get_index * element_size);
		tempRy = *pThisRxBuf++;  // word R0 contains ID

		if (tempRy & BUFFER_XTD_MASK) {
			// extended ID?
			pRxMailbox->info.id = tempRy & BUFFER_EXT_ID_MASK;
		} else {
			// standard ID
			pRxMailbox->info.id = (tempRy & BUFFER_STD_ID_MASK) >> 18;
		}

		tempRy = *pThisRxBuf++;  // word R1 contains DLC & timestamps
		dlc = (tempRy & BUFFER_DLC_MASK) >> 16;
		pRxMailbox->info.length = dlcToMsgLength[dlc];
		pRxMailbox->info.timestamp = tempRy & BUFFER_RXTS_MASK;
		/* copy the data from the buffer to the mailbox */
		pRxData = (uint8_t *) pThisRxBuf;

		for (idx = 0; idx < pRxMailbox->info.length; idx++)
			pRxMailbox->data[idx] = *pRxData++;

		// acknowledge reading the fifo entry
		*fifo_ack_reg = get_index;
		/* return entries remaining in FIFO */
	}

	return (fill_level);
}

/**@}*/

